<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/hexo/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/hexo/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/hexo/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/hexo/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/hexo/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/hexo/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/hexo/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="开发笔记,">










<meta name="description" content="上周，开发了一款基于腾讯音视频服务（TRTC）的视频会议类的web应用。在聊具体实现之前，我想先聊聊背景，吐槽吐槽，虽然吐槽并不能解决任何实际问题，但既然是个人的博客空间，就允许我任性的撒个娇吧。因为时间仓促，这个项目给到我们的实际开发时间只有5天，而这5天里，我们经历了以下事件：1.没有具体的规划，没有原型设计，没有界面设计，团队内部的沟通问题，导致了我们在接手项目的时候几乎是一张白纸，一切都得">
<meta name="keywords" content="开发笔记">
<meta property="og:type" content="article">
<meta property="og:title" content="快速开发一款音视频直播应用">
<meta property="og:url" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/index.html">
<meta property="og:site_name" content="Tony&#39;s blog">
<meta property="og:description" content="上周，开发了一款基于腾讯音视频服务（TRTC）的视频会议类的web应用。在聊具体实现之前，我想先聊聊背景，吐槽吐槽，虽然吐槽并不能解决任何实际问题，但既然是个人的博客空间，就允许我任性的撒个娇吧。因为时间仓促，这个项目给到我们的实际开发时间只有5天，而这5天里，我们经历了以下事件：1.没有具体的规划，没有原型设计，没有界面设计，团队内部的沟通问题，导致了我们在接手项目的时候几乎是一张白纸，一切都得">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/bb.jpg">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/bb2.jpg">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/1.png">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/2.png">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/3.png">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/4.png">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/5.png">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/6.png">
<meta property="og:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/7.png">
<meta property="og:updated_time" content="2020-03-30T07:35:32.863Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="快速开发一款音视频直播应用">
<meta name="twitter:description" content="上周，开发了一款基于腾讯音视频服务（TRTC）的视频会议类的web应用。在聊具体实现之前，我想先聊聊背景，吐槽吐槽，虽然吐槽并不能解决任何实际问题，但既然是个人的博客空间，就允许我任性的撒个娇吧。因为时间仓促，这个项目给到我们的实际开发时间只有5天，而这5天里，我们经历了以下事件：1.没有具体的规划，没有原型设计，没有界面设计，团队内部的沟通问题，导致了我们在接手项目的时候几乎是一张白纸，一切都得">
<meta name="twitter:image" content="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/bb.jpg">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/hexo/',
    scheme: 'Muse',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Tony'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://tony_df.coding.net/2020/03/30/快速开发一款音视频直播应用/">





  <title>快速开发一款音视频直播应用 | Tony's blog</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/hexo/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Tony's blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">学着码代码,学着码人生;</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/hexo/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-question-circle"></i> <br>
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/hexo/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-question-circle"></i> <br>
            
            Tags
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/hexo/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-question-circle"></i> <br>
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://tony_df.coding.net/hexo/2020/03/30/快速开发一款音视频直播应用/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Tony">
      <meta itemprop="description" content>
      <meta itemprop="image" content="/hexo/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Tony's blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">快速开发一款音视频直播应用</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2020-03-30T10:34:56+08:00">
                2020-03-30
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>上周，开发了一款基于腾讯音视频服务（TRTC）的视频会议类的web应用。在聊具体实现之前，我想先聊聊背景，吐槽吐槽，虽然吐槽并不能解决任何实际问题，但既然是个人的博客空间，就允许我任性的撒个娇吧。<br>因为时间仓促，这个项目给到我们的实际开发时间只有5天，而这5天里，我们经历了以下事件：<br>1.没有具体的规划，没有原型设计，没有界面设计，团队内部的沟通问题，导致了我们在接手项目的时候几乎是一张白纸，一切都得靠我们自己完成，而上面传达下来的指令只有一条，“务必完成”；<br>2.本来定了7天的开发，后续又受到要提前测试的通知，时间被缩短到了5天；<br>3.到第5天的时候，早上5点左右，又临时通知新增一场会议，而需求和之前我们设计的需求并不相同。注意，新增的这场会议，在之前，作为开发人员，毫不夸张，我是一无所知的，却被要求在上午9点完成新的流程修改和准备好测试环境。我想问，新增的需求我不需要了解吗，早上5点提需求，为了赶进度这几天每天2点才睡觉，你意思是让我5点就立刻起来整理？就算我整理出来了，程序不需要调整吗？调整后不需要测试吗？这些都是分分钟都能做的事儿吗？<br>4.因为被邀嘉宾的建议，在正式开始直播的当天，系统有被强制要求改版，而调整的时间可以精确到分钟，具体来说，只有40分钟左右，因为两场直播，同一天开始，虽然后一场是测试彩排，但在这期间，上一场可是正式直播，且为不间断直播；总而言之就是，在重合的时间里，既要保证第一场直播不能间断，又要保证第二场直播彩排满足改版要求。<br>从一个正常人的角度，以上任何一点，应该都属于是不合理的要求，如果不是亲身经历，我甚至会认为这是在故意刁难！<br>好了， 吐槽就戛然而止吧，特朗普也说了，或许这就是人生吧~<br>————————————————娇气的分割线——————————————————<br>先来说一下我们这个系统的大概需求，<br>1.要有基本的人员信息认证；<br>2.可以实时监控在线的用户人数，并向指定的用户发送呼叫，用户接听后进入指定的会议房间；<br>3.满足多人同时进入会议，可以自主控制麦克风和摄像头的开关，分享屏幕等基本功能；<br>4.会议全程为在线直播<br>基本就是这些，对应的，基础的功能模块有<br>1.登录认证<br>2.实时通信<br>3.视频会议<br>4.在线直播<br>在对应的，我们采用的解决方案入下<br>web框架：layui<br>通信框架：signalr<br>视频会议：trtc sdk for web<br>在线直播：lss<br>通过模块化的工作模式，来缩短我们的工作周期。再来说下具体实现<br>1.登录认证<br>这个我就不多说了，这块因为模型很简单，唯一相对耗时的部分就是在用户数据导入的部分，但也比较简单，忽略不计了吧。</p>
<p>2.通信框架<br>关于SignalR，我在之前有单独写过一篇博客介绍过（传送门：<a href="https://tony_df.gitee.io/hexo/2019/11/07/winform%E6%A1%8C%E9%9D%A2%E7%A8%8B%E5%BA%8F%E5%88%A9%E7%94%A8SignalR%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E5%8C%96%E9%9B%86%E4%B8%AD%E5%8D%87%E7%BA%A7/" target="_blank" rel="noopener">https://tony_df.gitee.io/hexo/2019/11/07/winform%E6%A1%8C%E9%9D%A2%E7%A8%8B%E5%BA%8F%E5%88%A9%E7%94%A8SignalR%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E5%8C%96%E9%9B%86%E4%B8%AD%E5%8D%87%E7%BA%A7/</a>），这里用到的和那篇里写的东西差不多，只是因为有了具体的业务，在代码量和功能点上相对多一些<br>这里我就简单介绍下我遇到的坑吧<br>第一个是跨域，因为是在.net core上集成SignalR，在Startup里要注入相关服务，具体代码如下；<br>首先是ConfigureServices里添加如下代码</p>
<figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//配置跨域</span></span><br><span class="line">services.AddCors(options =&gt;</span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//登录用户使用</span></span><br><span class="line">    options.AddPolicy(<span class="string">"any"</span>, builder =&gt;</span><br><span class="line">    &#123;</span><br><span class="line">        builder.WithOrigins(</span><br><span class="line">            <span class="string">"https://live.xiaoxiaotong.net/"</span></span><br><span class="line">            )</span><br><span class="line">        .AllowAnyMethod()</span><br><span class="line">        .AllowAnyHeader()</span><br><span class="line">        .AllowCredentials();</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">//公开使用</span></span><br><span class="line">    options.AddPolicy(<span class="string">"all"</span>, builder =&gt;</span><br><span class="line">    &#123;</span><br><span class="line">        builder.WithOrigins(<span class="string">"*"</span>)</span><br><span class="line">        .AllowAnyMethod()</span><br><span class="line">        .AllowAnyHeader();</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">//注入signalr</span></span><br><span class="line">services.AddSignalR();</span><br></pre></td></tr></table></figure>

<p>其次在Configure里添加</p>
<figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//开发环境用all，生产环境建议用any</span></span><br><span class="line">app.UseCors(<span class="string">"any"</span>);</span><br><span class="line">app.UseEndpoints(endpoints =&gt;</span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//集线器的访问地址，.net core 3.0以后的写法和2.2之前略有不同，当前是3.1</span></span><br><span class="line">    endpoints.MapHub&lt;Core.MyHub&gt;(<span class="string">"/MyHub"</span>);</span><br><span class="line">    endpoints.MapControllers();</span><br><span class="line">    endpoints.MapControllerRoute(</span><br><span class="line">        name: <span class="string">"default"</span>,</span><br><span class="line">        pattern: <span class="string">"&#123;controller=Home&#125;/&#123;action=Index&#125;/&#123;id?&#125;"</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>至此系统上的跨域配置就完成了，需要注意的是，如果你的公司环境采用了反向代理技术，需要在反向代理的配置里增加websocket的消息转发，因为signalr框架帮我们在客户端和服务端自动选择通信协议，依次是，websocket-&gt;sse-&gt;http长连接，如果我们反向代理没有做转发，signalr会在降级到sse是提示握手失败的错误。因为它检测到服务器已经是支持sse了，但因为代理转发的问题，会一直报错，且signalr也不会在继续降级，所以需要配置反向代理的转发设置；<br>以下为nginx的配置方式</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 转发websocket需要的设置</span></span><br><span class="line">proxy_set_header X-Real_IP <span class="variable">$remote_addr</span>;</span><br><span class="line">proxy_set_header Host <span class="variable">$host</span>;</span><br><span class="line">proxy_set_header X_Forward_For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">proxy_http_version 1.1;</span><br><span class="line">proxy_set_header Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line">proxy_set_header Connection <span class="string">'upgrade'</span>;</span><br></pre></td></tr></table></figure>

<p>将其添加到server_name配置项下面即可；<br>关于signalr，我在之前的博客里也推荐过比较好的介绍类文章，这里就不在赘述了；<br>然后，我想多提一句关于认知的问题，因为我在开发到这里的时候，为了效率，希望能使用上websocket协议。这需要服务器支持，而iis8.0以下的版本是不支持websocket协议的，也就是我需要部署的项目版本只能是Linux内核的服务器或者Windows Server 2012及以上版本的服务器。当我提出相应申请的时候，我们小组的领导非常支持也积极帮我协调资源。<br>但令人惊讶的是，负责资源调配的另一位领导，在询问具体情况时，非常肯定甚至非常自以为是的跟我们说，“websocket不就是http协议吗？支持http就肯定支持websocket！还申请什么服务器，用现在2008版本的就行，你说不行那是你的问题，跟服务器没关系”，当我试图解释的时候，该领导也非常不屑的戴上了某不知名品牌的耳机，一副高高挂起的样子，呵~<br>对于他的问题，我想说，自行车和汽车都是基于公路的，你能说他们俩是一样的东西吗？<br>世界上有个东西，叫Google，如果你不知道，或者你访问不到，中国还有个东西，叫百度！自己要是有不确定或者困惑的问题，建议先上这两个地方查查，虽然这上面胡说的人也挺多，但在信息技术方面的问题，他们给出的结果还是非常值得参考的。<br><img src="bb.jpg" alt="bb"><br><img src="bb2.jpg" alt="bb2"></p>
<p>3.视频会议<br>这块呢，虽然是核心功能，但我觉得也并没有什么可说的，因为腾讯给出的api都很完善了，另外他们关于在各个平台的集成，都给出了sdk和完整的demo，我们无非就是结合具体的业务，抄抄腾讯的作业罢了。<br>因为是公司项目，具体的业务代码我就不列了，也说几个具体需要注意的点吧，<br>a).获取usersig<br>usersig是根据腾讯提供的算法，在服务端生成，需要appid和appkey作为加密参数，在服务端获取的时候，建议加密传输过程，.net的话，可以采用mvc框架提供的ValidateAntiForgeryToken方式，api的话，可以用jwt来做鉴权；<br>b).配置ssl证书<br>如果在本地测试的话，sdk支持localhost，但是如果在生产环境测试，需要提前配置ssl证书，http协议是不能正确访问腾讯服务器的。<br>c).分辨率设定<br>web版的话，视频信号的分辨率是自适应的，为了节省流量费用，建议设定好视频的清晰度</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//初始化流</span></span><br><span class="line"><span class="keyword">this</span>.localStream_ = TRTC.createStream(&#123;</span><br><span class="line">        audio: <span class="literal">true</span>,</span><br><span class="line">        video: <span class="literal">true</span>,</span><br><span class="line">        userId: <span class="keyword">this</span>.userId_,</span><br><span class="line">        cameraId: getCameraId(),</span><br><span class="line">        microphoneId: getMicrophoneId(),</span><br><span class="line">        mirror: <span class="literal">true</span></span><br><span class="line">    &#125;);</span><br><span class="line"><span class="comment">//设定清晰度，标清足够用了，清晰度越高，流量计费越快</span></span><br><span class="line"><span class="keyword">this</span>.localStream_.setVideoProfile(<span class="string">'480p'</span>);</span><br></pre></td></tr></table></figure>

<p>d).踢人操作<br>当前的踢人操作，腾讯给出的方案是服务端的接口，而目前我们由于使用了signalr，所以我们的踢人操作并没有使用腾讯提供的方案，而是基于即时通信来完成踢人。<br>大概的流程就是，在直播间内有一个权限高的人，他有踢人的权限，这个判定是在第一步身份验证的时候就做好了，而他可以获取直播间内所有人的id，可以定向的向他发送移除的消息，而接收人在接受到该消息后，会在收到弹窗提醒后退出当前房间。从而完成了踢人的操作，而不需要借助腾讯的服务端api。<br>，看下代码</p>
<figure class="highlight c#"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;summary&gt;</span></span></span><br><span class="line"><span class="comment"><span class="doctag">///</span> 踢出用户</span></span><br><span class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;/summary&gt;</span></span></span><br><span class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;param name="user_id"&gt;</span><span class="doctag">&lt;/param&gt;</span></span></span><br><span class="line"><span class="comment"><span class="doctag">///</span> <span class="doctag">&lt;returns&gt;</span><span class="doctag">&lt;/returns&gt;</span></span></span><br><span class="line">[<span class="meta">ValidateAntiForgeryToken</span>]</span><br><span class="line">[<span class="meta">HttpPost</span>]</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">async</span> Task&lt;IActionResult&gt; <span class="title">RemoveUser</span>(<span class="params"><span class="keyword">string</span> user_id</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Response resp = <span class="keyword">new</span> Response();</span><br><span class="line">    <span class="keyword">await</span> myHub.Clients.User(user_id).SendAsync(<span class="string">"ReceiveMessage"</span>, <span class="keyword">new</span> &#123; message = <span class="string">"remove"</span> &#125;);</span><br><span class="line">    resp.code = <span class="number">1</span>;</span><br><span class="line">    resp.message = <span class="string">"移除用户指令已发送"</span>;</span><br><span class="line">    <span class="keyword">return</span> Json(resp);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">removeUser</span>(<span class="params">user_id,username</span>) </span>&#123;</span><br><span class="line">    swal(&#123;</span><br><span class="line">        title: <span class="string">"提示"</span>,</span><br><span class="line">        text: <span class="string">"确定要将"</span> + username + <span class="string">"移出当前房间吗?"</span>,</span><br><span class="line">        icon: <span class="string">"warning"</span>,</span><br><span class="line">        buttons: [<span class="string">'取消'</span>, <span class="string">'确定'</span>],</span><br><span class="line">    &#125;)</span><br><span class="line">        .then(<span class="function">(<span class="params">sure</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (sure) &#123;</span><br><span class="line">                $.post(<span class="string">"@Url.Action("</span>RemoveUser<span class="string">")"</span>, &#123; <span class="string">"user_id"</span>: user_id, <span class="string">'__RequestVerificationToken'</span>: token &#125;, <span class="function"><span class="keyword">function</span> (<span class="params">json</span>) </span>&#123;</span><br><span class="line">                    <span class="keyword">if</span> (json.code == <span class="number">1</span>) &#123;</span><br><span class="line">                        spop(<span class="string">"移出房间指令发送成功"</span>, <span class="string">"success"</span>);</span><br><span class="line">                        <span class="built_in">console</span>.log(json);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">signalr_connection.on(<span class="string">"ReceiveMessage"</span>, <span class="function"><span class="keyword">function</span> (<span class="params">json</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (json &amp;&amp; json.message == <span class="string">"remove"</span>) &#123;</span><br><span class="line">        swal(<span class="string">"您被管理员移出了房间"</span>, &#123; <span class="attr">icon</span>: <span class="string">"warning"</span>, <span class="attr">buttons</span>: <span class="literal">false</span>, <span class="attr">timer</span>: <span class="number">3000</span>  &#125;)</span><br><span class="line">        .then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            leave();</span><br><span class="line">            <span class="built_in">window</span>.location.href = <span class="string">"@Url.Action("</span>logOff<span class="string">")?user_id="</span> + chatinfo.id;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<p>e).软件环境<br>因为trtc也是基于webRTC协议的，所以浏览器内核需要支持WebRTC协议，所以，建议在用户使用系统的时候，检测客户端环境，如果环境不符，引导用户去下载chrome浏览器。</p>
<p>4.直播推流<br>这一块，我就不多说了，因为我的同事在直播这块非常有经验，说是一个人撑起了整个公司的直播体系也不为过。经验这个东西，是学不来的，一定要经历过，才能达到这个级别，因为直播就代表现场可能会有N种情况的突发状况，如果你没有经验，生瓜蛋子一个，即便有理论有技术，就是没经验，运气好直播没突发状况还行，运气不好，就可能毁了一场直播，而有经验的话，即便是遇到突发状况，你的经验也会帮你把损失降到最低，这就是根本的区别。<br>另外在简单介绍下我们用到的服务吧。当前国内三朵云和其他云基本都有直播类的服务，我们用的是百度的lss，官方的文档传送门：<a href="https://cloud.baidu.com/doc/LSS/index.html?from=productToDoc" target="_blank" rel="noopener">https://cloud.baidu.com/doc/LSS/index.html?from=productToDoc</a>。可能有人会问，你们用腾讯的视频服务，为什么直播还用百度的，不直接都用腾讯的？因为音视频的服务是第一次用，而直播是第N次用，我也说了，我们的同事非常有经验，尽管腾讯也支持，但实际情况才是最有参考价值的，所以，这个就不多说了。<br>好了，今天的分享差不多就这些，因为是公司的项目，不能把仓库地址分享出来，但前面我提到的另外一篇博客有关于通信部分的完整代码。另外多说一句，腾讯的音视频服务还是挺好用的，我们实际测试的时候一次引入10路信号也可以很稳定，但是引入的信号数量和对网络环境的要求是成正比的，信号量越多，对网络环境要求越高。所以正式使用的时候需要注意一下，这些内容，sdk的介绍文档里倒是都有，就是看你看的仔不仔细了，而且流量计费的时候，挺坑的，大家用的时候，注意监控！简单分享几张成品图吧<br><img src="1.png" alt="1"><br><img src="2.png" alt="2"><br><img src="3.png" alt="3"><br><img src="4.png" alt="4"><br><img src="5.png" alt="5"><br><img src="6.png" alt="6"><br><img src="7.png" alt="7"></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/hexo/tags/开发笔记/" rel="tag"># 开发笔记</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/hexo/2020/02/06/2020年，开启地狱模式/" rel="next" title="2020年，开启地狱模式">
                <i class="fa fa-chevron-left"></i> 2020年，开启地狱模式
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/hexo/2020/04/02/分享一个处理视频文件的利器-2/" rel="prev" title="分享一个处理视频文件的利器-2">
                分享一个处理视频文件的利器-2 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
        <!-- Go to www.addthis.com/dashboard to customize your tools -->
<div class="addthis_inline_share_toolbox">
  <script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5bbb2338b87602f0" async="async"></script>
</div>

      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zOTA1My8xNTU4MA"></div>
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">Tony</p>
              <p class="site-description motion-element" itemprop="description">学习总结</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/hexo/archives/">
              
                  <span class="site-state-item-count">58</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/hexo/tags/index.html">
                  <span class="site-state-item-count">7</span>
                  <span class="site-state-item-name">tags</span>
                </a>
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Tony</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Muse</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/hexo/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/hexo/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/hexo/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/hexo/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/hexo/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/hexo/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/hexo/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/hexo/js/src/motion.js?v=5.1.4"></script>



  
  

  
  <script type="text/javascript" src="/hexo/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/hexo/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/hexo/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  
    <script type="text/javascript">
      (function(d, s) {
        var j, e = d.getElementsByTagName(s)[0];
        if (typeof LivereTower === 'function') { return; }
        j = d.createElement(s);
        j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
        j.async = true;
        e.parentNode.insertBefore(j, e);
      })(document, 'script');
    </script>
  












  





  

  

  

  
  

  

  

  

</body>
</html>
